﻿using System;
using System.Collections.Generic;
using System.Text;
using Vortex.Drawing;
using Vortex.Input;

namespace Vortex.Tutorials.PixelAndVertexShaders {

    ///<summary></summary>
    class PixelAndVertexShaders : Game {
        Texture _SampleTexture;
        VertexShader _twistShader;
        PixelShader _blurShader;

        float _BlurStrength = 2.0f;
        Vector2 _TwistPoint;
        int _TesselationLevel = 50;
        bool _WireFrame;

        public PixelAndVertexShaders() {
            Window.Size = new System.Drawing.Size(1024, 680);
			ChangeDisplayModeOnAltEnter = false;

            _TwistPoint = new Vector2(Window.Size.Width / 2, Window.Size.Height / 2);

            Keyboard.KeyUp += delegate(VirtualKey key) {
                if (key == VirtualKey.Escape) {
                    Terminate();
                }
            };

            Keyboard.KeyDown += delegate(VirtualKey key) {
                switch (key) {
                    case VirtualKey.Q:
                        _BlurStrength = Math.Min(_BlurStrength + 0.5f, 5f);
                        break;
                    case VirtualKey.A:
                        _BlurStrength = Math.Max(_BlurStrength - 0.5f, 0f);
                        break;
                    case VirtualKey.W:
                        _WireFrame = !_WireFrame;
                        break;
                    case VirtualKey.G:
                        _TesselationLevel = Math.Max(10, _TesselationLevel - 10);
                        break;
                    case VirtualKey.T:
                        _TesselationLevel = Math.Min(100, _TesselationLevel + 10);
                        break;
                }
            };

            Mouse.ButtonDown += delegate(MouseButtonActionInfo info) {
                _TwistPoint = (Vector2)info.Location;
            };

			Mouse.Move += delegate(MouseMoveActionInfo info) {
				if (info.IsLeftButtonDown) {
					_TwistPoint = (Vector2)info.Location;
				}
			};
			
        }

        protected override void Load() {
            _SampleTexture = new Texture(@"{graphics}\chameleon.jpg");
            //loading shaders
            _twistShader = new VertexShader(@"{shaders}\twist.vs");
            _blurShader = new PixelShader(@"{shaders}\blur.ps");
        }

        protected override void Unload() {
            _SampleTexture.Dispose();
            //shaders should be disposed too
            _twistShader.Dispose();
            _blurShader.Dispose();
        }

        protected override void Update(GameTime time) {
        }

        protected override void Render(Canvas2D canvas) {
            canvas.Clear(ColorU.Black);

            //each of shader is set for specified scope. result of setting shader is ShaderContext which allows setup shader parameters
            using (canvas <= _blurShader)
            using (canvas <= _twistShader) {                
                //single pixel offset in scale 0..1
				_blurShader.Params.Set("TexelOffset", _SampleTexture.InvSize);
                //blur amount
				_blurShader.Params.Set("BlurStrength", _BlurStrength);

                //set up origin point for twisting
				_twistShader.Params.Set("TwistOriginPoint", _TwistPoint);
				_twistShader.Params.Set("TwistGradient", 200f);                                          // strength is 1:1 on this length
				_twistShader.Params.Set("TwistStrength", (float)Math.Cos(Time.TotalGameTime) * 0.75f);    // angle of bend in BendGradient

				//TODO: return wireframe mode option
				canvas.DrawTessellatedSprite(canvas.Region.Deflate(new Vector2(100, 60)), _SampleTexture.ToSprite(), ColorU.White, _TesselationLevel, _TesselationLevel);
            }
            canvas.DrawTextLayout(SpriteFont.Console, canvas.Region.Deflate(new Vector2(4, 4)), string.Format("Mouse left click - change twist point\nQ, A - Blur Strength (Value = {0:F1})\nT, G - Tesselation segments count ({1})\n\nEsc - Exit", _BlurStrength, _TesselationLevel), TextLayout.Left | TextLayout.Bottom, ColorU.White);
        }
    }

}
